﻿#include "bytearraystream.h"
#include "metaproperty.h"
#include "objectserilize.h"
#include <assert.h>

struct SerilizeInfo {
	MetaInfo meta;
	std::shared_ptr<IObjectSerilizer> Serilizer;
};

struct SerilizeContext
{
public:
	std::unordered_map<std::string, SerilizeInfo> infos;
	std::mutex m;
};

static SerilizeContext gContext;
static unsigned char gFlag = 'S';

class DefaultSerilizer :public IObjectSerilizer
{
public:
	DefaultSerilizer(MetaInfo meta);

	//使用已构造好的对象进行序列化
	void Serilize(void* target, DataOutputStream& stream) override;
	//对已构造好的对象进行反序列化
	void UnSerilize(void* target, DataInputStream& stream) override;

private:
	MetaInfo meta;
	std::unordered_map<std::string,int> SerilizableProperties;
};

ByteArray ObejctSerilize::Serilize(void * target, const MetaInfo & meta)
{
	ByteArray content;
	{
		BytearrayOutputStream btai;
		DataOutputStream stream(&btai);
		{
			std::lock_guard<std::mutex> lock(gContext.m);

			if (!gContext.infos.count(meta.ClassName())) {
				std::cerr << "Serilize:Error Serilizer Not Found!Please use RegisterSerilizer" << std::endl;
				return {};
			}

			auto & info = gContext.infos[meta.ClassName()];
			info.Serilizer->Serilize(target, stream);
		}
		content = btai.GetByteArray();
	}

	ByteArray ret;
	{
		BytearrayOutputStream btai;
		DataOutputStream stream(&btai);
		stream << gFlag;
		stream << meta.ClassName();
		stream << content;
		ret = btai.GetByteArray();
	}

	return ret;
}

ByteArray ObejctSerilize::SerilizeObj(Reflectable * target)
{
	return Serilize(dynamic_cast<void*>(target),target->GetMetaInfo());
}

ObejctSerilize::UnSerilizeResult ObejctSerilize::UnSerilize(const ByteArray & s, void * target, MetaInfo meta)
{
	ObejctSerilize::UnSerilizeResult ret;
	ret.isSuccess = false;
	ret.target = NULL;

	std::lock_guard<std::mutex> lock(gContext.m);

	ByteArray content;
	std::string className;
	{
		BytearrayInputStream btai(s.data(), s.size());
		DataInputStream stream(&btai);
		unsigned char flag;
		stream >> flag;

		if (flag != gFlag) {
			std::cerr << "Serilize:Error Serilize Failed,Content Not Legal" << std::endl;
			return ret;
		}

		stream >> className;

		if (meta.IsValid() && className != meta.ClassName()) {
			std::cerr << "Serilize:Error content ClassName is Not Same as Given MetaInfo's" << std::endl;
			return ret;
		}

		if (!gContext.infos.count(className)) {
			std::cerr << "Serilize:Error Serilizer Not Found!Please use RegisterSerilizer" << std::endl;
			return ret;
		}

		stream >> content;
	}

	auto & info = gContext.infos[className];
	if (!target) {
		if (info.meta.IsDefaultCreatable()) {
			std::cerr << "Serilize:Error Cannot Default Create an Object:" << info.meta.ClassName() << std::endl;
		}
		target = info.meta.Create();
		meta = info.meta;
	}

	{
		BytearrayInputStream btai(content.data(), content.size());
		DataInputStream stream(&btai);
		info.Serilizer->UnSerilize(target, stream);

		ret.isSuccess = true;
		ret.meta = meta;
		ret.target = target;
	}

	return ret;
}

Reflectable * ObejctSerilize::UnSerilizeObj(const ByteArray & s, Reflectable * target)
{
	MetaInfo info;
	if (target) {
		info = target->GetMetaInfo();
	}

	auto ret = UnSerilize(s, dynamic_cast<void*>(target), info);

	if (ret.isSuccess) {
		return ret.meta.MetaCast(ret.target);
	}

	return nullptr;
}

void ObejctSerilize::RegisterSerilizer(const MetaInfo & meta, IObjectSerilizer * serilizer)
{
    std::string className = meta.ClassName();\
    bool isNameNotDuplicated = gContext.infos.count(className);
    assert(isNameNotDuplicated);

	if (!serilizer) {
		serilizer = new DefaultSerilizer(meta);
	}

	SerilizeInfo info;
	info.meta = meta;
	info.Serilizer.reset(serilizer);

	std::lock_guard<std::mutex> lock(gContext.m);

	gContext.infos[className] = info;
}

bool isSerilizable(MetaProperty prop) {

	if (!prop.isReadable() || !prop.isWritable())
	{
		return false;
	}

	for (auto &i : prop.GetPropertyInfo()) {
		if (i == "DisableSerilize") {
			return false;
		}
	}

	return true;
}

DefaultSerilizer::DefaultSerilizer(MetaInfo meta)
{
	this->meta = meta;

	int cnt = meta.PropertyCount();
	for (int i = 0; i < cnt; i++) {
		auto prop = meta.GetProperty(i);
		if (isSerilizable(prop)) {
			SerilizableProperties[prop.Name()] = i;
		}
	}
}

void DefaultSerilizer::Serilize(void * target, DataOutputStream& stream)
{
	stream << (int)SerilizableProperties.size();
	for (auto i : SerilizableProperties) {
		auto prop = meta.GetProperty(i.second);
		stream << prop.Name();
		stream << prop.GetValue(target);
	}
}

void DefaultSerilizer::UnSerilize(void * target, DataInputStream& stream)
{
	int propertyCount = 0;
	stream >> propertyCount;

	for (auto i = 0; i < propertyCount; i++) {
		std::string Name;
		Variant Value;
		stream >> Name;
		stream >> Value;

		int index = SerilizableProperties.at(Name);

		auto prop = meta.GetProperty(index);
		if (!prop.isValid()) {
			continue;
		}
		
		prop.SetValue(target, Value);
	}
}
